﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using LockCrypt.Core;
using Newtonsoft.Json;

namespace LockCrypt.DAL {
    public class JSONConverters {
        /// <summary>
        /// Converts a UNIX time to a .NET DateTime.
        /// </summary>
        /// <param name="unixTime">The unix time.</param>
        /// <returns></returns>
        public static DateTime UNIXTimeToDateTime(double unixTime) {
            //return new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(unixTime);
            return new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(unixTime).ToLocalTime();
        }

        /// <summary>
        /// Converts a .NET DateTime to UNIX time.
        /// </summary>
        /// <param name="time">The DateTime.</param>
        /// <returns></returns>
        public static double DateTimeToUNIXTime(DateTime time) {
            TimeSpan span = (time - new DateTime(1970, 1, 1).ToLocalTime());
            TimeSpan offset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now);
            double t = span.TotalSeconds - offset.TotalSeconds;
            if(t > 1104537600) {
                return (t);
            } else {
                return 1800000000;
            }
        }

        /// <summary>
        /// initializes a new Account from a raw line of the database file
        /// </summary>
        /// <param name="serializer">The JSON serializer.</param>
        /// <param name="rawLine">The line read from the database file.</param>
        public static IAccount JSONToAccount(JsonSerializer serializer, string rawLine) {
            JSONAccount jso = (JSONAccount)serializer.Deserialize(new System.IO.StringReader(rawLine), typeof(JSONAccount));
            IAccount account = new AccountBase() {
                Name = jso.Name,
                Icon = jso.Icon,
                ParentID = string.Equals(jso.Parent, "lockcrypt", StringComparison.InvariantCultureIgnoreCase) ? null : jso.Parent,
                Notes = jso.Notes,
                Template = new TemplateBase() {
                    ID = jso.TypeID,
                    Name = jso.Type,
                    ShowNotes = jso.ShowNotes,
                }
            };
            string created = jso.Created,
                   modified = jso.Modified;
            account.Created = UNIXTimeToDateTime(double.Parse(created.Substring(0, created.Length - 3)));
            account.Modified = UNIXTimeToDateTime(double.Parse(modified.Substring(0, modified.Length - 3)));
            for(int i=0;i< jso.Fields.Length;i++) {
            //foreach(Dictionary<string, string> field in jso.Fields) {
                IField field = JSONSegmentToField(jso.Fields[i]);
                field.SortIndex = i;
                account.Fields.Add(field);
            }
            return account;
        }

        /// <summary>
        /// initializes a new Group from a raw line of the database file
        /// </summary>
        /// <param name="serializer">The JSON serializer.</param>
        /// <param name="rawLine">The line read from the database file.</param>
        /// <returns></returns>
        public static IGroup JSONToGroup(JsonSerializer serializer, string rawLine) {
            JSONGroup jso = (JSONGroup) serializer.Deserialize(new System.IO.StringReader(rawLine), typeof(JSONGroup));
            IGroup group = new GroupBase() {
                ID = jso.Name,
                Name = jso.Name,
                ParentID = string.Equals(jso.Parent, "lockcrypt", StringComparison.InvariantCultureIgnoreCase) ? null : jso.Parent
            };
            return group;
        }

        /// <summary>
        /// Initializes a new Account Type from a raw line of the database file
        /// </summary>
        /// <param name="serializer">The JSON serializer.</param>
        /// <param name="rawLine">The line read from the database file.</param>
        public static ITemplate JSONToTemplate(JsonSerializer serializer, string rawLine) {
            JSONTemplate jso = (JSONTemplate)serializer.Deserialize(new System.IO.StringReader(rawLine), typeof(JSONTemplate));
            ITemplate template = new TemplateBase() {
                ID = jso.ID,
                Name = jso.Name,
                ShowNotes = jso.ShowNotes,
                CanUserEdit = !jso.IsProtected,
            };
            for(int i=0;i< jso.Fields.Length;i++) {
                template.Fields.Add(new FieldBase() { Name=jso.Fields[i], SortIndex = i});
            }
            return template;
        }

        /// <summary>
        /// Converts a serial JSON segment to an IField.
        /// </summary>
        /// <param name="jsonField">The json field.</param>
        /// <returns>The IField equivalent.</returns>
        public static IField JSONSegmentToField(Dictionary<string, string> jsonField) {
            IField field = new FieldBase() {
                Value = jsonField["Value"]
            };
            string rawName = jsonField["Name"];
            if(rawName.Length >= 3 && rawName.StartsWith("~}")) {
                switch(rawName[2]) {
                    case '*':
                        field.Meta = FieldMetaData.Password;
                        if(rawName.Length > 3)
                            field.Name = rawName.Substring(3);
                        break;
                    case 'u':
                        field.Meta = FieldMetaData.Url;
                        if(rawName.Length > 3)
                            field.Name = rawName.Substring(3);
                        break;
                    case '#':
                        field.Meta = FieldMetaData.Phone;
                        if(rawName.Length > 3)
                            field.Name = rawName.Substring(3);
                        break;
                    default:
                        field.Name = rawName;
                        break;
                }
            } else {
                field.Name = rawName;
            }
            return field;
        }
    }

    /// <summary>
    /// Enables parsing from JSON using Json.NET
    /// </summary>
    public class JSONTemplate {
        public string ID { get; set; }
        public string Name { get; set; }
        public bool IsProtected { get; set; }
        public bool ShowNotes { get; set; }
        public string[] Fields { get; set; }
        public JSONTemplate() { }
        /// <summary>
        /// Enables easier serialization to JSON.
        /// </summary>
        /// <param name="type">The type.</param>
        public JSONTemplate(ITemplate type) {
            this.ID = type.ID;
            this.Name = type.Name;
            this.ShowNotes = type.ShowNotes;
            this.IsProtected = !type.CanUserEdit;
            this.Fields = SerializeFields(type.Fields);
        }

        private static string[] SerializeFields(IList<IField> fields) {
            /*string[] fieldMap = new string[fields.Count];
            var orderedFields = fields.OrderBy(f => f.SortIndex);
            for(int i = 0; i < fieldMap.Length; i++) {
                fieldMap[i] = fieldMap.v
            }*/
            string[] fieldMap = fields.OrderBy(f=>f.SortIndex).Select(f=>f.Name).ToArray();
            return fieldMap;
        }
    }
    /// <summary>
    /// Enables parsing from JSON using Json.NET
    /// </summary>
    public class JSONAccount {
        public string Name { get; set; }
        public string Type { get; set; }
        public string TypeID { get; set; }
        public string Icon { get; set; }
        public string Parent { get; set; }
        public string Created { get; set; }
        public string Modified { get; set; }
        public bool ShowNotes { get; set; }
        public string Notes { get; set; }
        public Dictionary<string, string>[] Fields { get; set; }
        public JSONAccount() { }

        /// <summary>
        /// Enables easier serialization to JSON.
        /// </summary>
        /// <param name="account">The account.</param>
        public JSONAccount(IAccount account) {
            this.Name = account.Name;
            //this.Type = account.Type;
            this.Icon = account.Icon;
            this.Parent = account.Name; // parent ID not supported
            this.Created = JSONConverters.DateTimeToUNIXTime(account.Created).ToString();
            this.Modified = JSONConverters.DateTimeToUNIXTime(account.Modified).ToString();
            this.Fields = new Dictionary<string, string>[account.Fields.Count];
            int i = 0;
            foreach(IField field in account.Fields) {
                string metaPrefix = string.Empty;;
                if(FieldBase.GetMetaState(field.Meta, FieldMetaData.Password)) {
                    metaPrefix = "~}*";
                } else if(FieldBase.GetMetaState(field.Meta, FieldMetaData.Url)) {
                    metaPrefix = "~}u";
                } else if(FieldBase.GetMetaState(field.Meta, FieldMetaData.Phone)) {
                    metaPrefix = "~}#";
                }
                var fieldDictionary = new Dictionary<string, string> {
                        {"Name", metaPrefix+field.Name.ToString()}, // key
                        {"Value", Convert.ToString(field.Value)} // value
                    };
                this.Fields[i] = fieldDictionary;
                i++;
            }
            this.Notes = account.Notes;
            if(account.Template == null) {
                this.ShowNotes = true;
                this.TypeID = string.Empty;
            } else {
                this.ShowNotes = account.Template.ShowNotes;
                this.TypeID = account.Template.ID;
            }
        }
    }
    /// <summary>
    /// Enables parsing from JSON using Json.NET
    /// </summary>
    public class JSONGroup {
        public string Name { get; set; }
        public string Parent { get; set; }
        public string Created { get; set; }
        public string Modified { get; set; }
        public JSONGroup() { }
        /// <summary>
        /// Enables easier serialization to JSON.
        /// </summary>
        /// <param name="group">The group.</param>
        public JSONGroup(IGroup group) {
            this.Name = group.Name;
            this.Parent = string.IsNullOrEmpty(group.ParentID) ? "LockCrypt" : group.ParentID;
            //this.Created = JSONConverters.DateTimeToUNIXTime(group.Created).ToString();
            //this.Modified = JSONConverters.DateTimeToUNIXTime(group.Modified).ToString();
            this.Created = JSONConverters.DateTimeToUNIXTime(DateTime.Now).ToString();
            this.Modified = JSONConverters.DateTimeToUNIXTime(DateTime.Now).ToString();
        }
    }
}